package com.xixibaby.redis.aspect;

import cn.hutool.core.util.StrUtil;
import com.xixibaby.core.SuperAspect;
import com.xixibaby.core.SuperRequest;
import com.xixibaby.core.Assert;
import com.zengtengpeng.operation.RedissonObject;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.util.function.Function;

@org.aspectj.lang.annotation.Aspect
public class RedisCacheAspect implements SuperAspect {


    @Autowired
    private RedissonObject redissonObject;

    @Override
    @Pointcut("@annotation(com.xixibaby.redis.aspect.RedisCache)")
    public void pointCut() {

    }

    @Around(value = "pointCut()&&@annotation(redisCache)")
    public Object pointProcess(ProceedingJoinPoint point, RedisCache redisCache) throws Throwable {
        Method method = getMethod(point);
        Class<?> declaringClass = method.getDeclaringClass();
        String cacheKey;
        //如果不需要全局配置
        if(!redisCache.globle()){
            Object[] args = point.getArgs();
            SuperRequest superRequest = (SuperRequest) args[0];
            cacheKey = StrUtil.format("{}.{}.{}",declaringClass.getName(),method.getName(),superRequest.getUserId());
        }else{
            cacheKey = StrUtil.format("{}.{}",declaringClass.getName(),method.getName());
        }
        Object value = redissonObject.getValue(cacheKey);
        if(Assert.notEmpty(value)){
            return value;
        }else{
            Object proceed = point.proceed();
            redissonObject.delete(cacheKey);
            redissonObject.setValue(cacheKey,proceed,redisCache.ttl());
            return proceed;
        }
    }


    public <T> T getMethodSignature(ProceedingJoinPoint point, Function<MethodSignature,T> function){
        Signature sig = point.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        return function.apply(msig);
    }


    @SneakyThrows
    public Method getMethod(ProceedingJoinPoint point)  {
        MethodSignature msig = getMethodSignature(point, methodSignature -> methodSignature);
        Object target = point.getTarget();
        return target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
    }



}
